﻿using ZyGame.Execute;
using System.Collections.Generic;
using System;
using UnityEngine;
using ZyGame.Game;

namespace ZyGame.Avatar
{
    internal class AvatarInstance : Singleton<AvatarInstance>
    {
        private AvatarBuilded avatar;

        public bool EnsureAvatarInitialized()
        {
            if (avatar != null)
            {
                return true;
            }
            Client.Events.Notify(EventNames.ERROR_MESSAGE_NOTICE, ErrorInfo.NOT_INITIALIZED_AVATAR);
            return false;
        }

        public bool EnsureAvatarBuildedGroupName(string groupName)
        {
            if (!EnsureAvatarInitialized())
            {
                return false;
            }
            if (avatar.groupName != groupName)
            {
                Client.Events.Notify(EventNames.ERROR_MESSAGE_NOTICE, string.Format(ErrorInfo.ELEMENT_GROUP_NOT_THE_SAME, avatar.groupName, groupName));
                return false;
            }
            return true;
        }

        /// <summary>
        /// 初始化编辑器
        /// </summary>
        /// <param name="args">初始化参数</param>
        public void Initialized(AvatarOptions initData)
        {
            if (avatar != null)
            {
                avatar.Dispose();
            }
            Client.Game.GetWorld("").NewEntity();
            avatar = new AvatarBuilded();
            BonesConfig.instance.Initialized(initData.config);
            AvatarSetting.user = initData.userId;
            AvatarSetting.pid = initData.pid;
            CameraCtrl.instance.Hide(ControllerState.Pen);
            avatar.Initialize(initData.skeleton, initData.version, initData.crc, initData.address);
        }


        /// <summary>
        /// 清理部件
        /// </summary>
        /// <param name="element"></param>
        public void ClearElement(int element)
        {
            this.EnsureAvatarInitialized();
            avatar.ClearElement((Element)element);
        }

        /// <summary>
        /// 将部位显示在视图中心
        /// </summary>
        public void ShowInView(int element)
        {
            this.EnsureAvatarInitialized();
            avatar.ShowInView((Element)element);
        }

        /// <summary>
        /// 导出配置
        /// </summary>
        /// <param name="configName">保存的配置名</param>
        public void ExportConfig(string configName)
        {
            this.EnsureAvatarInitialized();
            avatar.ExportConfig(configName);
        }

        /// <summary>
        /// 获取部件数据
        /// </summary>
        /// <param name="element">部位枚举</param>
        public ElementData GetElementData(int element)
        {
            this.EnsureAvatarInitialized();
            return avatar.GetElementData((Element)element);
        }

        public ElementComponent GetElementComponent(int element)
        {
            if (!this.EnsureAvatarInitialized())
            {
                return default;
            }
            return avatar.GetElementComponent((Element)element);
        }

        /// <summary>
        /// 导入配置
        /// </summary>
        /// <param name="config">配置数据</param>
        public void ImportConfig(string config)
        {
            this.EnsureAvatarInitialized();
            avatar.ImportConfig(config);
        }

        /// <summary>
        /// 设置部件模型
        /// </summary>
        /// <param name="elementData">部位数据</param>
        public void SetElementData(List<ElementData> elements)
        {
            this.EnsureAvatarInitialized();

            if (elements == null)
            {
                Client.Events.Notify(EventNames.ERROR_MESSAGE_NOTICE, ErrorInfo.THE_ELEMENT_DATA_CAN_NOT_BE_NULL_OR_EMPTY);
                return;
            }
            Client.Running.TryGetOrCreate(elements.GetHashCode().ToString(), out ParallelRunnable parallelRunnable);
            avatar.SetElementData(parallelRunnable, elements.ToArray());
            parallelRunnable.DoFinish(Client.Events.Notify, EventNames.SET_ELEMENT_DATA_COMPLATED, default(object));
        }

        /// <summary>
        /// 设置部件模型
        /// </summary>
        /// <param name="elementData">部位数据</param>
        public void SetElementData(ParallelRunnable executed, ElementData element)
        {
            this.EnsureAvatarInitialized();

            if (element == null)
            {
                Client.Events.Notify(EventNames.ERROR_MESSAGE_NOTICE, ErrorInfo.THE_ELEMENT_DATA_CAN_NOT_BE_NULL_OR_EMPTY);
                return;
            }

            avatar.SetElementData(executed, element);
            executed.DoFinish(Client.Events.Notify, EventNames.SET_ELEMENT_DATA_COMPLATED, default(object));
        }

        /// <summary>
        /// 合并Avatar
        /// </summary>
        public void Combine()
        {
            this.EnsureAvatarInitialized();
            avatar.Combine();
        }

        /// <summary>
        /// 上传部件资源
        /// </summary>
        /// <param name="element">部件位置</param>
        /// <param name="fileDataString">文件数据</param>
        public void UploadAsset(int element)
        {
            this.EnsureAvatarInitialized();
            void Runnable_OpenFileComplated(object args)
            {
                Client.Events.Unregister(EventNames.OPEN_FILE_COMPLATED, Runnable_OpenFileComplated);
                avatar.UploadElementAsset((Element)element, string.Empty, (byte[])args);
            }
            Client.Events.Register(EventNames.OPEN_FILE_COMPLATED, Runnable_OpenFileComplated);
            Client.File.OpenFileWindow();
        }

        /// <summary>
        /// 预览
        /// </summary>
        /// <param name="element">部位枚举</param>
        public void PreviewAsset(int element)
        {
            this.EnsureAvatarInitialized();
            void Runnable_OpenFileComplated(object args)
            {
                Client.Events.Unregister(EventNames.OPEN_FILE_COMPLATED, Runnable_OpenFileComplated);
                avatar.PreviewElement((Element)element, (byte[])args);
            }
            Client.Events.Register(EventNames.OPEN_FILE_COMPLATED, Runnable_OpenFileComplated);
            Client.File.OpenFileWindow();
        }

        /// <summary>
        /// 隐藏部位
        /// </summary>
        /// <param name="element"></param>
        public void DisableElement(int element)
        {
            this.EnsureAvatarInitialized();
            this.avatar.SetElementActived((Element)element, false);
        }

        /// <summary>
        /// 显示部位
        /// </summary>
        /// <param name="element"></param>
        public void EnableElement(int element)
        {
            this.EnsureAvatarInitialized();
            this.avatar.SetElementActived((Element)element, true);
        }

        /// <summary>
        /// 播放动作
        /// </summary>
        /// <param name="name"></param>
        public void PlayAction(string name)
        {
            if (avatar is null || avatar.animator is null)
            {
                return;
            }
            avatar.animator?.Play(name);
        }

        public void PlayFaceAction(Dictionary<int, float> emotionData)
        {
            if (avatar is null || avatar.skinned is null)
            {
                return;
            }

            if (avatar.skinned.sharedMesh.blendShapeCount is 0)
            {
                Client.Console.WriteError("Not find blend shape data with the skinned mesh renderer");
                return;
            }

            foreach (var item in emotionData)
            {
                avatar.skinned.SetBlendShapeWeight(item.Key, item.Value);
            }
        }
    }
}
